#ifndef _project_shared_h_
#define _project_shared_h_

#include "shared.h"

// Custom widgets must be declared before the layout is included

#include "FilterField.h" // Handy dandy extension of EditField into a proper filter field

// Things that need to be shared across all classes in current project.

#include <CtrlLib/CtrlLib.h>
#include <GridCtrl/GridCtrl.h>

using namespace Upp;

// Capture some macro values

#define PROJECT_NAME jammit // PROJECT_SPECIFIC:  Change per project: (Note: Must be lowercase for linux)
#define PROJECT_TTL "Jammit" // PROJECT_SPECIFIC: Displayed in MainWin title
#define PROJECT_INTERNAL_NAME PROJECT_TTL

// __FUNCSIG__ defined on MSC for stringified name
#define MYERR(msg)           MyErr(msg, __FILE__, __LINE__, __FUNCTION__)

// Types of error: User tried to do something we can't do, internal code error, device or service failed
void MyErr(String msg, const char *file, long line, const char *functionname);

// Display message, the SQL error message, the hex error #, the actual SQL statement executed
#define DBERR(msg, lst)      LOG((msg) << DeQtf(lst.GetLastError()) << ", " << lst.GetErrorCodeString() << ", " << lst.GetErrorStatement())
#define LAYOUTFILE <svn/jammit/project.lay>
#include <CtrlCore/lay.h>

//#include "timer.h" // This header was created for windows; does not function in linux


// Create global since it blows chunks as singleton; referenced in MainWin.h and elsewhere for timing
// Usage: display on screen: lastoptimer.SetText(timer.ToString());  // Shows elapsed time since instantiation
// Call reset to reset timer
//extern Timer &timer; 

// Configuration control; XML based; tag controls the actual file created so as to keep performance of initial screen good
extern StaticMutex sMtx;

// Rect conversion: Use format of Ultimate's Rect ToString function for writing to the Config.xml file
#define RECT_STORE_FORMAT "\[%d,%d] - \[%d,%d]"

// TODO: MainWin icon appears to be taller than necessary, widening title bar unnecessarily
// Cannot be defined in project_shared.h since source code is defined in iml_source.h and it is forced to be redefined!
//#include "Draw/iml.h" // Cannot use this since I am sharing images across several CPP files
// http://www.ultimatepp.org/srcdoc$CtrlLib$Tutorial$en-us.html
// Following 3 lines necessary to set the TaskBar icon, which is based on the current window icon, not the app icon, which is set in the resource file.
#include "image_shared.h"
//#define IMAGECLASS MyImages
//#define IMAGEFILE "project.iml"

#include <Draw/iml_header.h> 

class Config {
protected:
	bool changed;
	bool read;
	String configPath;
	String configXML;
	XmlNode n;

public:
	enum LoadSourceEnum { LoadFromHome, LoadFromRun };

protected:
	void LoadModuleConfigFile(const char *modTag, LoadSourceEnum loadSourceEnum) {
		
		Mutex::Lock __(sMtx);
		switch (loadSourceEnum) {
		case LoadFromRun:
			configPath = ~ConfigFile(String().Cat() << modTag << ".ini");
			configXML = LoadFile(configPath);
			break;
		case LoadFromHome:
			configPath << GetHomeDirectory() << "\\" << GetExeTitle() << "\\" << modTag << ".ini";
			configXML = LoadFile(configPath);
			break;
		default:
			Exclamation("Unrecognized LoadSourceEnum");
		}
	}
	
public:

	void Store() {
		
		//PromptOK(AsXML(n));
		Mutex::Lock __(sMtx);
		if (!SaveFile(configPath, AsXML(n))) {
		}
	}

	Config(const char *modTag, LoadSourceEnum loadSourceEnum) {
		
		changed = read = false;
		LoadModuleConfigFile(modTag, loadSourceEnum);
		n = ParseXML(configXML);
	}

	~Config() {
		Store();
	}
	
	String Get(const char *id, const String& def) {
		
		const XmlNode &node = n[id];
		if (node.IsVoid()) {
			return def;
		} else {
			read = true;
			int c = node.GetCount();
			if (c == 0) {
				return def;
			}
			for (int i = 0; i < c; i++) {
				const XmlNode &childNode = node.Node(i);
				if (childNode.GetType() == XML_TEXT) {
					// TODO: Compare to see if any change; check for other values, attributes
					return childNode.GetText();  // Sets current nodes contents to text
					break;
				}
			}
			return String();
		}
	}

	String Get(const char *id) {
		
		return Get(id, String());
	}

	Upp::int64 Get(const char *id, const int64 def) {
		
		String sdef = AsString(def);
		return ScanInt64(Get(id, sdef));
	}
	
	int Get(const char *id, const int def) {
		
		String sdef = AsString(def);
		return ScanInt(Get(id, sdef));
	}

	void Set(const char *id, const int val) {
		
		String sval = AsString(val);
		Set(id, sval);
	}
		
	Rect Get(const char *id, Rect& def) {
		
		String sdef = def.ToString();
		sdef = Get(id, sdef);
		int x, y, cx, cy;
		int r = sscanf(sdef, RECT_STORE_FORMAT, &x, &y, &cx, &cy); 
		return Rect(x,y,cx,cy);
	}
 
	void Set(const char *id, const Rect& val) {
		
		// Don't take a change on ToString not changing; make our own
		
		int x, y, cx, cy;
		// Convert to storage format
		x = val.left; y = val.top; cx = val.right; cy = val.bottom;		
		Set(id, Format(RECT_STORE_FORMAT, x, y, cx, cy));
	}

	void Set(const char *id, const String & sval) {
		
		if (n.FindTag(id) < 0) {
			changed = true; // This will be a new tag; flag this
			// Log to config change .hist
		}
		
		XmlNode &node = n.GetAdd(id); // Gets or creates a node of type tag
		
		int c = node.GetCount();  // Get children count.  The first one must be text and we will replace it
		if (c == 0) {
			node.AddText(sval);
		} else {
			for (int i = 0; i < c; i++) {
				XmlNode &childNode = node.At(i);
				if (childNode.GetType() == XML_TEXT) {
					// TODO: Compare to see if any change; check for other values, attributes
					childNode.CreateText(sval);  // Sets current nodes contents to text
					break;
				}
			}
		}
		
		changed = true;

		// Hopefully this replaces existing text
	}
};

/*
class Integer : public Moveable<Integer> {
public:
	uint64 n;
	virtual uint64 Get() const { return n; }
	
	Integer(int n) : n(n) {}
	Integer(unsigned int n) : n(n) {}
	Integer(byte n) : n(n) {}
	Integer(uint64 n) : n(n) {}
	Integer(int64 n) : n(n) {}
	Integer(short n) : n(n) {}
	Integer(char n) : n(n) {}
	unsigned GetHashValue() const {
		return chr[KIND] ? LHashValue() : (unsigned)CombineHash(w[0], w[1], w[2], w[3]);
	}
};
*/


#endif

